package org.budo.wxpay.api;

import java.util.HashMap;
import java.util.Map;

import org.budo.support.lang.util.MapUtil;
import org.budo.support.lang.util.RandomUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.wxpay.util.WxpayUtil_0;

import com.github.wxpay.sdk.WXPay;

import lombok.extern.slf4j.Slf4j;

/**
 * @author limingwei
 */
@Slf4j
public class WxPayApiImpl extends AbstractWxPayApi {
    @Override
    public CloseOrderResponse closeOrder(CloseOrderRequest request) {
        return new CloseOrderResponse();
    }

    @Override
    public Map<String, String> refund(Map<String, String> map) {
        WXPay wxPay = this.wxpay(new RefundRequest());
        try {
            Map<String, String> refund = wxPay.refund(map);

            log.info("#31 postRefund, refund=" + refund + ", map=" + map);
            return refund;
        } catch (Exception e) {
            log.error("#31 map=" + map + ", e=" + e, e);
            return new HashMap<String, String>();
        }
    }

    @Override
    public OrderQueryResponse orderQuery(OrderQueryRequest request) {
        Map<String, String> requestMap = new HashMap<String, String>();
        requestMap.put("out_trade_no", request.getOutTradeNo());

        WXPay wxpay = this.wxpay(request);
        Map<String, String> responseMap = WxpayUtil_0.orderQuery(wxpay, requestMap);

        if (null == responseMap || responseMap.isEmpty()) {
            log.error("#106 responseMap=" + responseMap + ", requestMap=" + requestMap);
            return null;
        }

        return new OrderQueryResponse() //
                .setErrCode(responseMap.get("err_code")) //
                .setErrCodeDes(responseMap.get("err_code_des")) //
                .setTradeState(responseMap.get("trade_state")) //
                .setTradeStateDesc(responseMap.get("trade_state_desc"));
    }

    /**
     * https://segmentfault.com/a/1190000017803841
     */
    @Override
    public UnifiedOrderResponse unifiedOrder(UnifiedOrderRequest request) {
        if ("JSAPI".equalsIgnoreCase(request.getTradeType())) {
            return this.unifiedOrder_JSAPI(request);
        }

        if ("MWEB".equalsIgnoreCase(request.getTradeType())) {
            return this.unifiedOrder_MWEB(request);
        }

        if ("NATIVE".equalsIgnoreCase(request.getTradeType())) {
            return this.unifiedOrder_NATIVE(request);
        }

        throw new RuntimeException("#134 request=" + request);
    }

    @Override
    public UnifiedOrderResponse unifiedOrder_JSAPI(UnifiedOrderRequest request) {
        String notifyUrl = this.notifyUrl(request);

        Map<String, String> requestMap = new HashMap<String, String>();
        requestMap.put("body", request.getBody());
        requestMap.put("out_trade_no", request.getOutTradeNo());
        requestMap.put("device_info", "");
        requestMap.put("fee_type", "CNY");
        requestMap.put("total_fee", request.getTotalFee() + "");
        requestMap.put("spbill_create_ip", request.getSpbillCreateIp());
        requestMap.put("notify_url", notifyUrl);
        requestMap.put("trade_type", "JSAPI");
        requestMap.put("openid", request.getOpenId());

        WXPay wxpay = this.wxpay(request);
        Map<String, String> responseMap = WxpayUtil_0.unifiedOrder(wxpay, requestMap);

        if (null == responseMap || null == responseMap.get("result_code") || !StringUtil.equals("SUCCESS", responseMap.get("result_code"))) {
            log.error("#257 responseMap=" + responseMap + ", requestMap=" + requestMap);

            throw new RuntimeException("#258 responseMap=" + responseMap);
        }

        return new UnifiedOrderResponse() //
                .setPrepayId(responseMap.get("prepay_id"));
    }

    @Override
    public UnifiedOrderResponse unifiedOrder_MWEB(UnifiedOrderRequest request) {
        String notifyUrl = this.notifyUrl(request);

        Map<String, String> requestMap = new HashMap<String, String>();
        requestMap.put("body", request.getBody());
        requestMap.put("out_trade_no", request.getOutTradeNo());
        requestMap.put("device_info", "");
        requestMap.put("fee_type", "CNY");
        requestMap.put("total_fee", request.getTotalFee() + "");
        requestMap.put("spbill_create_ip", request.getSpbillCreateIp());
        requestMap.put("notify_url", notifyUrl);
        requestMap.put("trade_type", "MWEB");

        WXPay wxpay = this.wxpay(request);
        Map<String, String> responseMap = WxpayUtil_0.unifiedOrder(wxpay, requestMap);

        if (null == responseMap || null == responseMap.get("result_code") || !StringUtil.equals("SUCCESS", responseMap.get("result_code"))) {
            log.error("#326 responseMap=" + responseMap + ", requestMap=" + requestMap);

            throw new RuntimeException("#258 responseMap=" + responseMap);
        }

        return new UnifiedOrderResponse() //
                .setPrepayId(responseMap.get("prepay_id")) //
                .setMwebUrl(responseMap.get("mweb_url"));
    }

    @Override
    public UnifiedOrderResponse unifiedOrder_NATIVE(UnifiedOrderRequest request) {
        String notifyUrl = this.notifyUrl(request);

        Map<String, String> requestMap = new HashMap<String, String>();
        requestMap.put("body", request.getBody());
        requestMap.put("out_trade_no", request.getOutTradeNo());
        requestMap.put("device_info", "");
        requestMap.put("fee_type", "CNY");
        requestMap.put("total_fee", request.getTotalFee() + "");
        requestMap.put("spbill_create_ip", request.getSpbillCreateIp());
        requestMap.put("notify_url", notifyUrl);
        requestMap.put("trade_type", "NATIVE"); // 此处指定为扫码支付

        WXPay wxpay = this.wxpay(request);
        Map<String, String> responseMap = WxpayUtil_0.unifiedOrder(wxpay, requestMap);

        if (null == responseMap || null == responseMap.get("result_code") || !StringUtil.equals("SUCCESS", responseMap.get("result_code"))) {
            log.error("#257 responseMap=" + responseMap + ", requestMap=" + requestMap);
            throw new RuntimeException("#258 responseMap=" + responseMap);
        }

        return new UnifiedOrderResponse() //
                .setPrepayId(responseMap.get("prepay_id")) //
                .setCodeUrl(responseMap.get("code_url"));
    }

    @Override
    public Map<String, String> jsapi_getBrandWCPayRequest(String prepay_id) {
        long timeStamp = System.currentTimeMillis();
        String nonceStr = RandomUtil.randomNumberString(32);

        Map<String, String> map = MapUtil.stringMap( //
                "appId", this.getAppId(), //
                "timeStamp", timeStamp + "", //
                "nonceStr", nonceStr, //
                "package", "prepay_id=" + prepay_id, //
                "signType", "MD5" //
        );

        String paySign = WxpayUtil_0.generateSignature(map, this.getApiKey());
        map.put("paySign", paySign);

        return map;
    }

    @Override
    public Map<String, Object> wxa_requestPayment(String prepayId) {
        String timestamp = System.currentTimeMillis() / 1000 + "";
        String nonceStr = RandomUtil.randomNumberString(32);

        String tmp = "appId=" + this.getAppId() //
                + "&nonceStr=" + nonceStr //
                + "&package=prepay_id=" + prepayId //
                + "&signType=MD5" //
                + "&timeStamp=" + timestamp //
                + "&key=" + this.getApiKey();

        String paySign = WxpayUtil_0.MD5(tmp).toUpperCase();

        return MapUtil.stringObjectMap("timeStamp", timestamp //
                , "nonceStr", nonceStr //
                , "package", "prepay_id=" + prepayId // 统一下单接口返回的 prepay_id 参数值，提交格式如：prepay_id=wx2017033010242291fcfe0db70013231072
                , "paySign", paySign //
                , "signType", "MD5");
    }
}